package nancal.mp.web.open

//import nbcp.base.config.ActionDocBeanGather

import ch.qos.logback.classic.Logger
import io.swagger.annotations.ApiOperation
import nancal.mp.db.mongo.entity.admin.AdminUser
import nancal.mp.db.mongo.extend.doLogin
import nancal.mp.db.mongo.extend.getAppDeploySetting
import nancal.mp.db.mongo.mor
import nancal.mp.db.redis.rer
import nancal.mp.service.GoogleAuthenticatorService
import nancal.mp.web.sys.LoginInfo_Controller
import nbcp.base.annotation.mvc.OpenAction
import nbcp.base.comm.ApiResult
import nbcp.base.comm.JsonResult
import nbcp.base.comm.ListResult
import nbcp.base.db.LoginUserModel
import nbcp.base.extend.*
import nbcp.base.utils.*
import nbcp.mvc.sys.LoginUser
import nbcp.mvc.sys.token
import nbcp.myoql.db.mongo.query

import org.apache.commons.codec.digest.DigestUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.web.bind.annotation.*
import java.io.File
import java.time.LocalDate
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.http.HttpSession

/**
 * Created by udi on 17-3-19.
 */
@RestController
@RequestMapping("/open")
@OpenAction
class Open_Controller(val googleAuthenticatorService: GoogleAuthenticatorService) {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }

    class TokenModel() {
        var token = "";
        var corpLogo = ""
        var corpName = ""
        var systemName = ""
        var corpIcon = ""
        var loginPage = ""
    }

    @GetMapping("/get-token")
    fun getAuth(): ApiResult<TokenModel> {
        var model = TokenModel();
        model.token = CodeUtil.getCode();

        var setting = mor.dev.appDeploySetting.getAppDeploySetting()
        model.corpLogo = setting.corpLogo
        model.corpIcon = setting.corpIcon
        model.corpName = setting.corpName
        model.systemName = setting.systemName
        model.loginPage = setting.loginPage
        return ApiResult.of(model)
    }

//    @GetMapping("/doc")
//    fun doc(skip: Int, take: Int, name: String, tag: String): List<ApiDocDefine> {
//        var apis = ApiDocUtil.genApis("nancal.mp", { m, url, tags, apiName ->
//            if (tag.HasValue) {
//                return@genApis tags.any { it.contains(tag) }
//            }
//
//            if (name.HasValue) {
//                return@genApis apiName.contains(name);
//            }
//
//            return@genApis true;
//        }, { param ->
//            if (param.type == LoginUserModel::class.java) {
//                return@genApis false
//            }
//            return@genApis true
//        })
//        if (skip > 0) {
//            apis = apis.Skip(skip);
//        }
//
//        if (take > 0) {
//            apis = apis.take(take);
//        }
//        return apis;
//    }

    @ApiOperation(value = "base64md5")
    @PostMapping("/base64md5")
    fun base64md5(@RequestBody text: String): ApiResult<String> {
        var md5 = DigestUtils.md5(text);
        return ApiResult.of(Base64Util.encode2Base64(md5));
    }

    @ApiOperation(value = "退出登录")
    @PostMapping("/logout")
    fun logout(token: String, request: HttpServletRequest): JsonResult {
        rer.sys.token(request.token).deleteKey()
        request.session.invalidate();

        return JsonResult()
    }

    @GetMapping("/dict")
    fun dict(minLen: Int, maxLen: Int, total: Int): ListResult<String> {
        var list = ResourceUtil.readResourceContentText("public/dict.txt")
            .split("\n")
            .map { it.trim() }

        if (minLen > 2) {
            list = list.filter { it.length >= minLen };
        } else {
            list = list.filter { it.length >= 2 };
        }

        if (maxLen > 0) {
            list = list.filter { it.length <= maxLen };
        }

        var skip = MyUtil.getRandomNumber(1, Math.min(500, list.size / 10));
        return ListResult.of(list.Slice(skip, (if (total > 1) total else 5000) + skip));
    }

    @ApiOperation(value = "登录")
    @PostMapping("/login")
    fun login(
        loginName: String,
        password: String,
        validateCode: String,
        request: HttpServletRequest,
        response: HttpServletResponse,
        session: HttpSession
    ): ApiResult<AdminUser> {

        if (validateCode.length == 0) {
            return ApiResult.error("请输入验证码！")
        }
//        if (validateCode != rer.sys.imgValidateCode(request.token).get()) {
//            return ApiResult.error("验证码错误，请重试！")
//        }

        var loginUser = mor.admin.adminLoginUser.queryByLoginName(loginName).toEntity()
            .must()
            .elseThrow { "找不到用户" }

        if (loginUser.mfa1.HasValue && loginUser.mfa1ExpireAt != null && loginUser.mfa1ExpireAt!! >= LocalDate.now() && loginUser.mfa1 == validateCode) {
            //通过
        } else if (loginUser.totpKey.HasValue && !googleAuthenticatorService.authorize(
                loginUser.totpKey,
                validateCode.AsInt()
            )
        ) {
            return ApiResult.error("验证码错误，请重试！");
        }

//        rer.sys.token(request.token).deleteKey();


        var loginResult = mor.admin.adminUser.doLogin(loginName, password, request.token);
        if (loginResult.msg.HasValue) {
            return ApiResult.error(loginResult.msg);
        }

        rer.sys.token(request.token).set(loginResult.data.ToJson());

        return loginInfo.getMine(request.LoginUser, response)
    }

    @Autowired
    lateinit var loginInfo: LoginInfo_Controller

//    @ApiOperation(value = "获取登录者信息")
//    @PostMapping("/getLocations")
//    fun getLocations(session: HttpServletRequest): ListResult<IdName> {
//        var ret = ListResult<IdName>();
//
//        ret.data = mor.sys.sysDictionary.query()
//                .where { it.group mongoEquals SysDictionaryGroupEnum.LocationForSchool }
//                .select { it.name }
//                .toList(IdName::class.java)
//
//        return ret;
//    }

//    data class cn_cityModel(var c: Int, var n: String)

//    @PostMapping("/getChildCitys")
//    fun getChildCitys(code: Int, response: HttpServletResponse): JsonResult? {
//        var ret = JsonResult()
//        if (code == 0) {
//            return JsonResult("城市code不能为空")
//        }
//        if (code % 100 != 0) return ret;
//
//        var value = rer.sys.sysCityJson.get(code.toString());
//        if (value.HasValue) {
//            response.WriteJsonRawValue(value);
//            return null;
//        }
//
//
//        value = ApiResult(
//                data = mor.sys.sysCity.query()
//                        .where(mor.sys.sysCity.pcode mongoEquals code)
//                        .toList(CodeName::class.java)
//                        .map { cn_cityModel(it.code, it.name) }
//        )
//                .ToJson();
//
//
//        rer.sys.sysCityJson.set(code.toString(), value);
//
//        response.WriteJsonRawValue(value);
//        return null;
//    }

    @Value("\${spring.application.name}")
    var applicationName: String = "";


    @GetMapping("/log")
    fun log(
        filter: List<String>?, not: List<String>?, tail: Boolean?,
        extCount: Int = 0, matchLines: Int, help: Boolean?,
        f: List<String>?, c: Int = 0, n: Int = 0,
        request: HttpServletRequest
    ): String {
        if (!SpringUtil.context.environment.defaultProfiles.any { it.contains("dev") }) {
            return "非 dev!"
        }


        var logFile = (logger as Logger).getLoggerFile("FILE-OUT");


        var log_text = File(logFile).FilterLines(
            n.AsInt(matchLines),
            c.AsInt(extCount),
            f ?: filter ?: emptyList(),
            not ?: emptyList(),
            tail
                ?: true
        ).joinToString("\n")

        var help_html = "";
        if (help == true) {
            help_html = """<pre>
    日志参数,优先使用简写参数：
        filter:f  表示过滤匹配条件，可以多个
        not:      表示过滤匹配不满足条件的行，可以多个
        tail:     表示是否从最底部显示，默认是 true
        extCount:c 表示如果有 filter , not 的话，返回匹配行的前后多少行。
        matchLines:n 表示返回的总行数
</pre>
<hr />"""
        }

        return """<!DOCTYPE html>
<html>
<head><title>${applicationName} - 日志</title></head>
<body>${help_html}<pre>${log_text}</pre></body>
</html>
"""
    }

}
